(module-name <console.scm.terminal>)
(require <console.scm.console>)

(define terminal :: terminal.Terminal (<terminal.Terminal> console))

(define (get-capture-file)
  (terminal:getLogFile))

(define (open-capture file-name append-flag)
  (if (equal? file-name "jiffy-cancelled")
    (begin
      (newline)
      (display "open capture cancelled"))
    (begin
      (terminal:setLogFile (file-name:toString) append-flag))))
(define (close-capture)
  (terminal:setLogFile "" #f))

(define (deactivate)
  ((terminal:getTerminal):setEnabled #f))
(define (activate)
  ((terminal:getTerminal):setEnabled #t))
(define (activated?)
  ((terminal:getTerminal):isEnabled))

(define (start-terminal)
  (terminal:start 
    (if (not (eq? #!null (java.lang.System:getProperty "ser.port")))
      (java.lang.System:getProperty "ser.port")
      "no-default-port")
    57600)
  (let* ((term (terminal:getTerminal))
         (term-scroll (<javax.swing.JScrollBar>))
         (term-pane (<javax.swing.JPanel>))
         (split-pane :: javax.swing.JSplitPane (top-panel:getParent)))
           (frame:setPreferredSize (java.awt.Dimension 640 480))
           (frame:pack)
           (split-pane:setDividerLocation 300)
           (term-pane:setLayout (<java.awt.BorderLayout>))
           (split-pane:setTopComponent term-pane)
           (term:setResizeStrategy (de.mud.terminal.SwingTerminal:.RESIZE_SCREEN))
           (term:setScrollbar term-scroll)
           (term-pane:add term)
           (term-pane:add term-scroll (java.awt.BorderLayout:.EAST))
           (term-pane:setBackground (java.awt.Color:.BLACK))
           (console:setNextFocusableComponent term))
  ((field terminal 'serialPort):setFlowControlMode (gnu.io.SerialPort:.FLOWCONTROL_NONE))
  ((field terminal 'serialPort):setDTR #t)
  ((field terminal 'serialPort):setRTS #t)
  (disable-kermit)
)

(define (terminal-font-up)
  (let* ((term (terminal:getTerminal))
         (font (term:getFont)))
    (term:setFont
      (<java.awt.Font>
        (font:getName)
        (font:getStyle) 
        (+ (font:getSize) 1)))
        (frame:pack)))
(define (terminal-font-down)
  (let* ((term (terminal:getTerminal))
         (font (term:getFont)))
    (term:setFont
      (<java.awt.Font>
        (font:getName)
        (font:getStyle) 
        (- (font:getSize) 1)))
        (frame:pack)))
(define (get-background)
  ((terminal:getTerminal):getBackground))
(define (set-background c)
  (if (eq? c #!null)
    (display "cancelled")
    ((terminal:getTerminal):setBackground c)))
(define (get-foreground)
  ((terminal:getTerminal):getForeground))
(define (set-foreground c)
  (if (eq? c #!null)
    (display "cancelled")
    ((terminal:getTerminal):setForeground c)))
(define (colour-selector title default)
  (javax.swing.JColorChooser:showDialog (as <javax.swing.JFrame> frame) title (as <java.awt.Color> default)))


(define (disable-kermit) (terminal:setKermitEnabled #f))
(define (enable-kermit) (terminal:setKermitEnabled #t))
(define (kermit-enabled?) (terminal:getKermitEnabled))

(define busy-wait-cal 1)
(define (tsc) (terminal:readTimeStampCounter))
(define (cal-busy-wait)
  (let ((start (tsc)))
      (sleep 1)
      (let ((jiffies (- (tsc) start)))
         (set! busy-wait-cal (/ jiffies (* 1 (expt 10 9))))
         busy-wait-cal)))
(define cal-busy-wait-done #f)
(define (check-cal-busy-wait-done)
  cal-busy-wait-done)
(define (new-cal-busy-wait)
  (let ((start (tsc)))
      (set! cal-busy-wait-done #f)
      (future (begin (sleep 1) (set! cal-busy-wait-done #t)))
      (letrec ((next (lambda ()
                        (sleep 0.000000000001)
                        (if (not (check-cal-busy-wait-done)) (next))))) (next))
      (let ((jiffies (- (tsc) start)))
         (set! busy-wait-cal (/ jiffies (* 1 (expt 10 9))))
         busy-wait-cal)))
(define (busy-wait nanos)
   (let* ((end (+ (tsc) (* busy-wait-cal nanos))))
      (letrec ((next (lambda ()
                       (if (< (tsc) end)
                          (next)))))
         (next))))
(define (receive-from-dut count)
  (terminal:receiveFromDUT count))

(define (putch-dut ch)
  (let ((value (if (equal? (ch:getClass) (gnu.text.Char:.class)) (char->integer ch) ch)))
    (terminal:sendCommand value)))

(define (getch-dut spot)
  (letrec ((next (lambda (timeout)
                   (let ((buffer-count (get-dut-buffer-count)))
                     (if (< buffer-count (+ spot 1))
                       (if (> timeout 0)
                         (begin
                           (synchronized terminal:bufferLock (terminal:bufferLock:wait 50))
                           (next (- timeout (if (< buffer-count (get-dut-buffer-count)) 0 0.050))))
                         -1)
                       (list-ref (dut-buffer-list (get-dut-buffer)) spot))))))
    (next 5)))

;(define (getch-dut spot)
;   (letrec ((buffer-count (get-dut-buffer-count))
;            (wait-for-char-n (lambda ()
;                               (if (< (get-dut-buffer-count) (+ spot 1))
;                                  (if (< ((java.util.Calendar:getInstance):getTimeInMillis) timeout-time)
;                                     (begin
;                                       (synchronized terminal:bufferLock (terminal:bufferLock:wait 50))
;                                       (wait-for-char-n))
;                                     -1)
;                                  (list-ref (dut-buffer-list (get-dut-buffer)) spot)))))
;      (wait-for-char-n)))

(define (get-dut-buffer) (terminal:getDUTBuffer))
(define (get-dut-buffer-size) (terminal:getDUTBufferSize))
(define (get-dut-buffer-count) (terminal:getDUTBufferCount))
(define (dut-buffer-list dat)
  (letrec ((next (lambda (l n)
             (if (< n (get-dut-buffer-count))
               (next (append l (list (terminal.Terminal:getByte dat n))) (+ n 1))
               l))))
    (next (list ) 0)))

(define (no-lf str)
   (letrec ((next (lambda (l-new l-old)
                    (if (> (length l-old) 0)
                      (next (append l-new (list (if (eq? (car l-old) #\newline)
                                                  #\return
                                                  (car l-old))))
                            (cdr l-old))
                      l-new))))
      (next (list) str)))

(define (get-baud-rate)
  ((field (as <terminal.Terminal> terminal) 'serialPort):getBaudRate))
(define (set-baud-rate rate)
  (terminal:setBaudRate rate))
(define (dut-flush)
  (terminal:flushSerial))
(define (open-binary-input-file name)
  (fluid-let ((port-char-encoding #f)) (open-input-file name)))
(define (open-binary-output-file name)
  (fluid-let ((port-char-encoding #f)) (open-output-file name)))
(define (get-file-list fname)
  (let ((f (open-binary-input-file fname)))
    (letrec ((next (lambda ()
                     (if (not (eof-object? (peek-char f)))
                        (append (list (char->integer (read-char f))) (next))
                        (list )))))
      (let ((l (next)))
        (close-input-port f)
        l))))
(define-constant SOH 1)
(define-constant STX 2)
(define-constant ETX 3)
(define-constant ENQ 5)
(define-constant ACK 6)
(define-constant BEL 7)
(define-constant LF 10)
(define-constant CR 13)
(define-constant SO 14)
(define-constant SI 15)
(define-constant DLE 16)
(define-constant CLR 17)
(define-constant KEY 18)
(define-constant BIN 19)
(define-constant ASI 20)
(define-constant NAK 21)
(define-constant CAN 24)
(define-constant AST 42)

(define (puts-dut str)
  (map putch-dut (string->list str)))

(cal-busy-wait)
